#include "stdafx.h"
#include "imgui/imgui.h"
#include "layouts.h"
#include <sstream>

namespace Imgui
{
	void LayoutStyle::SetDefaults()
	{
		// rgba
		layoutBackground = 0x606060ff;
		titleBackground = 0x505050ff;
		layoutHighlight = 0xe0e0e0ff;
		layoutShadow = 0x303030ff;
		buttonNormal = 0x909090ff;
		buttonPressed = 0xf0a000ff;
		buttonSelected = 0xb0b0b0ff;
		buttonText = 0xffffffff;
		buttonTextShadow = 0x000000ff;
		buttonTextGhosted = 0xc0c0c0ff;
		textBackground = 0x000000ff;

		margin = 2;
		indentSize = 16;

		Render::FreeFont(m_pFont);
		m_pFont = Render::LoadFont("vera.ttf", 16);;
	}

	void LayoutStyle::SetFont(Render::Font* pFont)
	{
		if (m_pFont)
			Render::FreeFont(m_pFont);

		m_pFont = pFont;
	}

	LayoutStyle::~LayoutStyle()
	{
		Render::FreeFont(m_pFont);
	}

	void Ui::UiState::UpdateHot(uint32 hotFloat_)
	{
		if (hotFloat_ || !hotFloat)
			hot = hotCounter;

		hotFloat = hotFloat || hotFloat;
	}

	void Ui::UiState::PushClipRect(const Window& window)
	{
		Render::Rect rect;
		rect.x = window.x;
		rect.y = window.y;
		rect.w = window.width;
		rect.h = window.height;

		if (!clipRectStack.empty())
		{
			const Render::Rect& previous = clipRectStack.back();

			int x2 = rect.x + rect.w;
			int y2 = rect.y + rect.h;

			rect.x = max(rect.x, previous.x);
			rect.y = max(rect.y, previous.y);
			rect.w = min(rect.w, min(x2, previous.x + previous.w) - rect.x);
			rect.h = min(rect.h, min(y2, previous.y + previous.h) - rect.y);
		}

		Render::SetClipRect(&rect);
		clipRectStack.push_back(rect);
	}

	void Ui::UiState::PopClipRect()
	{
		clipRectStack.pop_back();

		if (clipRectStack.empty())
		{
			Render::SetClipRect(0);
		}
		else
		{
			Render::SetClipRect(&clipRectStack.back());
		}
	}

	void Ui::UiState::OnKeyDown(uint16 unicode)
	{
		if (unicode < 128)
			currentInput.key = (char) unicode; 
	}

	Layout::~Layout()
	{
		pUi->GetState().EndLayout();
	}

	FixedWindow::FixedWindow(Ui& ui, uint32 flags, const Window* pWindow_)
	{
		pUi = &ui;
		pUi->GetState().BeginLayout(Ui::UiState::LayoutType::FIXED_WINDOW, flags, pWindow_);
	}

	HorizontalList::HorizontalList(Ui& ui, uint32 flags, Window* pWindow_)
	{
		pUi = &ui;
		pUi->GetState().BeginLayout(Ui::UiState::LayoutType::HORIZONTAL_LIST, flags, pWindow_);
	}

	VerticalList::VerticalList(Ui& ui, uint32 flags, Window* pWindow_)
	{
		pUi = &ui;
		pUi->GetState().BeginLayout(Ui::UiState::LayoutType::VERTICAL_LIST, flags, pWindow_);
	}

	Table::Table(Ui& ui, uint32 flags, Window* pWindow_)
	{
		pUi = &ui;
		pUi->GetState().BeginLayout(Ui::UiState::LayoutType::TABLE, flags, pWindow_);
	}

	void Table::BeginRow()
	{
		pUi->GetState().column = 0;
	}

	void Table::EndRow()
	{
		pUi->GetState().row++;
	}

	Tree::Tree(Ui& ui, uint32 flags, Window* pWindow_)
	{
		pUi = &ui;
		ui.GetState().BeginLayout(Ui::UiState::LayoutType::VERTICAL_LIST, flags, pWindow_);
		ui.GetState().levels.clear();
		BeginBranch();
	}

	Tree::~Tree()
	{
		EndBranch();
	}

	void Tree::BeginBranch()
	{
		pUi->GetState().levels.push_back(0);
	}

	void Tree::EndBranch()
	{
		pUi->GetState().levels.pop_back();
	}

	/////////////////////////////////////////////////////////////////

	void Ui::Initialise()
	{
		m_pState = Ut::MakeShared(new UiState);
	}

	void Ui::Shutdown()
	{
		m_pState.Release();
	}

	LayoutStyle& Ui::GetStyle()
	{
		return m_pState->style;
	}

	Ui::UiState& Ui::GetState()
	{
		return *m_pState;
	}

	Frame::Frame(Ui& ui, Render::SurfacePtr pSurface, Window* pWindow_)
	{
		pUi = &ui;

		Assert(pUi->GetState().layoutStack.empty());

		ui.GetState().layoutCounter = 0;
		ui.GetState().hotCounter = 0;
		ui.GetState().pressedCounter = 0;
		ui.GetState().previousInput = ui.GetState().currentInput;
		ui.GetState().previousHot = ui.GetState().hot;
		ui.GetState().hot = -1;
		ui.GetState().hotFloat = false;

		auto mouse = App::GetMouseState();

		ui.GetState().currentInput.mouseX = mouse.x;
		ui.GetState().currentInput.mouseY = mouse.y;
		ui.GetState().currentInput.mouseL = mouse.left;
		ui.GetState().currentInput.mouseR = mouse.right;

		Window window(0, 0, Render::GetWidth(pSurface), Render::GetHeight(pSurface));
		ui.GetState().BeginLayout(Ui::UiState::LayoutType::FIXED_WINDOW, Imgui::EMPTY|Imgui::BORDERLESS, pWindow_ ? pWindow_ : &window);
	}

	Frame::~Frame()
	{
		pUi->GetState().currentInput.key = 0;
	}

	void Ui::Release()
	{
		m_pState->pressed = -1;
	}

	void Ui::SetCounter(int c)
	{
		if (m_pState->hot >= m_pState->hotCounter && m_pState->hot < c)
			m_pState->hot = -1;

		if (m_pState->pressed >= m_pState->pressedCounter && m_pState->pressed < c)
			m_pState->pressed = -1;

		m_pState->hotCounter = c;
		m_pState->pressedCounter = c;
	}

	bool Ui::DoTreeNode(const char* text, bool mayExpand, bool& expanded, bool& rClick, uint32 flags, Window* pWindow)
	{
		Window window;
		int level = (int) m_pState->levels.size() - 1;
		window.x = level * m_pState->style.indentSize + (level > 0 ? 18 : 0);

		m_pState->BeginLayout(Ui::UiState::LayoutType::HORIZONTAL_LIST, EXPAND|BORDERLESS|EMPTY|INDENT|ALLOW_OVERFLOW, &window);

		Render::SetClipRect(0);

		if (level == 0)
			DoLabel(">", BORDERLESS);
		
		if (mayExpand)
			expanded ^= DoButton(expanded ? "- " : "+", BORDERLESS);

		Window buttonWindow;
		bool click = DoButton(text, BORDERLESS|ON_MOUSE_DOWN|flags, &buttonWindow);
		rClick = DoButton(0, USE_INPUT_XY|BORDERLESS|EMPTY|ON_MOUSE_DOWN|R_MOUSE|REPEAT, &buttonWindow);

		if (pWindow)
			*pWindow = buttonWindow;

		m_pState->EndLayout(&window);

		Render::SetClipRect(0);

		window.height -= m_pState->style.margin;

		window.x = level * m_pState->style.indentSize + (level > 0 ? 18 : 0);
		m_pState->layoutStack.back()->AddItem(EXPAND|INDENT, &window);

		int midY = window.y + window.height / 2;

		if (m_pState->levels.back() == 0)
			m_pState->levels.back() = window.y - m_pState->style.margin * 2;

		if (level > 0)
		{
			int s = 8 + m_pState->style.margin;
			
			Render::DrawHLine(window.x - s, midY, window.x, m_pState->style.buttonNormal);
			Render::DrawVLine(window.x - s, m_pState->levels[level], midY, m_pState->style.buttonNormal);
		}

		m_pState->levels[level] = midY;

		return click;
	}

	int Ui::DoMenuStrip(const char* options[], int count, Window& out, Window* pWindow)
	{
		m_pState->BeginLayout(Ui::UiState::LayoutType::HORIZONTAL_LIST, EXPAND|BORDERLESS|NO_SEPARATION, pWindow);

		Imgui::Window buttonWindow;

		int selected = -1;

		for (int i = 0; i < count; i++)
		{
			if (DoButton(options[i], ON_MOUSE_DOWN|ON_MOUSE_UP|BORDERLESS|NO_SEPARATION, &buttonWindow))
			{
				selected = i;
				out.x = buttonWindow.x;
				out.y = buttonWindow.y + buttonWindow.height;
			}
		}

		DoLabel(" ", FIT|EXPAND|BORDERLESS|BUTTON);

		m_pState->EndLayout(pWindow);

		return selected;
	}

	int Ui::DoListBox(const char* items[], uint32 itemFlags[], int count, bool& rClick, uint32 flags, Window* pWindow)
	{	
		m_pState->BeginLayout(Ui::UiState::LayoutType::VERTICAL_LIST, flags|NO_SEPARATION, pWindow);

		int selected = -1;
		rClick = false;

		for (int i = 0; i < count; i++)
		{
			Window buttonWindow;
			if (DoButton(items[i], EXPAND|BORDERLESS|NO_SEPARATION|flags|(itemFlags ? itemFlags[i] : 0), &buttonWindow))
				selected = i;

			if (DoButton(0, USE_INPUT_XY|BORDERLESS|EMPTY|ON_MOUSE_DOWN|R_MOUSE|REPEAT, &buttonWindow))
			{
				rClick = true;
				selected = i;
			}
		}

		m_pState->EndLayout(pWindow);

		return selected;
	}

	int Ui::DoMenu(const char* options[], uint32 optionFlags[], int count, uint32 flags, Window* pWindow)
	{
		m_pState->BeginLayout(UiState::LayoutType::VERTICAL_LIST, NO_SEPARATION|USE_CACHED_SIZE|flags, pWindow);

		int selected = -1;
		int startCount = m_pState->pressedCounter;

		for (int i = 0; i < count; i++)
		{
			if (DoButton(options[i], FLOAT|EXPAND|BORDERLESS|NO_SEPARATION|ON_MOUSE_UP|flags|(optionFlags ? optionFlags[i] : 0)))
				selected = i;
		}

		m_pState->EndLayout(pWindow);

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool pressed = m_pState->pressed != -1 && (m_pState->pressed < startCount);

		if (selected == -1 && (!currentMouse || pressed))
			selected = count;

		return selected;
	}

	bool Ui::DoLabeledTextBox(const char* label, std::string& text, uint32 flags, Window* pWindow)
	{
		m_pState->BeginLayout(Ui::UiState::LayoutType::HORIZONTAL_LIST, flags|Imgui::BORDERLESS|Imgui::EXPAND, pWindow); 
		DoLabel(label); 
		bool triggered = DoTextBox(text, BACK); 
		m_pState->EndLayout(pWindow);
		return triggered;
	}

	bool Ui::DoLabeledIntBox(const char* label, int& n, uint32 flags, Window* pWindow)
	{
		m_pState->BeginLayout(Ui::UiState::LayoutType::HORIZONTAL_LIST, flags|Imgui::BORDERLESS|Imgui::EXPAND, pWindow); 
		DoLabel(label); 

		std::string text;
		std::stringstream ss; ss << n; text = ss.str();

		bool triggered = DoTextBox(text, BACK);

		if (triggered)
		{
			std::stringstream ss2(text); int i = 0; ss2 >> i; n = i;
		}

		m_pState->EndLayout(pWindow);
		return triggered;
	}

	bool Ui::DoTextBox(std::string& text, uint32 flags, Window* pWindow)
	{
		std::string outText = text;
		static std::string temp;

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			outText = temp;
			outText += "|";
		}

		if (outText == "")
			outText = " ";

		Window window;

		int width = GetWidth(m_pState->style.GetFont(), outText.c_str()) + m_pState->style.margin * 2;
		int height = GetHeight(m_pState->style.GetFont(), outText.c_str()) + m_pState->style.margin + 1;

		if (pWindow)
			window = *pWindow;

		window.width = max(width, window.width);
		window.height = max(height, window.height);

		m_pState->layoutStack.back()->AddItem(flags, &window);

		if (pWindow)
			*pWindow = window;

		// Render
		{
			m_pState->PushClipRect(window);

			if (window.width > 0 && window.height > 0)
			{
				Render::FillRect(window.x, window.y, window.x + window.width, window.y + window.height, m_pState->style.textBackground);
				Render::DrawText(window.x + min(window.width - width, 0) + m_pState->style.margin, window.y + 1, m_pState->style.GetFont(), outText.c_str(), m_pState->style.buttonText);
			}

			if (!(flags & BORDERLESS))
			{
				Render::DrawHLine(window.x, window.y, window.x + window.width - 1, m_pState->style.layoutShadow);
				Render::DrawVLine(window.x, window.y, window.y + window.height - 1, m_pState->style.layoutShadow);
				Render::DrawVLine(window.x + window.width - 1, window.y, window.y + window.height, m_pState->style.layoutHighlight);
				Render::DrawHLine(window.x, window.y + window.height - 1, window.x + window.width, m_pState->style.layoutHighlight);
			}

			m_pState->PopClipRect();
		}

		bool triggered = false;

		bool inside = (window.x <= m_pState->currentInput.mouseX && m_pState->currentInput.mouseX < window.x + window.width
					&& window.y <= m_pState->currentInput.mouseY && m_pState->currentInput.mouseY < window.y + window.height);

		if (inside)
			m_pState->UpdateHot(flags & FLOAT);

		if (flags & FORCE_FOCUS)
			m_pState->hot = -1;

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool previousMouse = (flags & R_MOUSE) ? m_pState->previousInput.mouseR : m_pState->previousInput.mouseL;

		bool click = !(flags & GHOSTED) && (currentMouse && (!previousMouse || ((flags & ON_MOUSE_UP) && m_pState->pressed == -1)));

		if (m_pState->previousHot == m_pState->hotCounter)
		{
			if (click)
			{
				m_pState->pressed = m_pState->pressedCounter;
				temp = text;
			}
		}
		else if (!(flags & FORCE_FOCUS) && (click && m_pState->pressed == m_pState->pressedCounter))
		{
			triggered = true;
			m_pState->pressed = -1;
			text = temp;
			temp = "";
		}

		if ((flags & FORCE_FOCUS) && m_pState->pressed != m_pState->pressedCounter)
		{
			m_pState->pressed = m_pState->pressedCounter;
			temp = text;
		}

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			char key = m_pState->currentInput.key;

			if (key)
			{
				if (key > 31 && key < 127)
					temp += m_pState->currentInput.key;

				if (key == 8) // backspace
				{
					if (temp.size() > 0)
						temp = temp.substr(0, temp.size() - 1);
				}

				if (key == 13)
				{
					triggered = true;
					m_pState->pressed = -1;
					text = temp;
					temp = "";
				}
			}
		}

		m_pState->hotCounter++;
		m_pState->pressedCounter++;

		return triggered;
	}

	bool Ui::DoVerticalScrollBar(int& offset, float proportion, uint32 flags)
	{
		Window window;
		window.width = 10;
		m_pState->layoutStack.back()->AddItem(flags|EXPAND, &window);

		int activeOffset = (int) (offset * proportion + 0.5f);

		Window activeWindow(window);
		activeWindow.y += activeOffset;
		activeWindow.height = (int) (proportion * window.height + 0.5f);

		// Render
		{
			if (window.width > 0 && window.height > 0)
			{
				uint32 colour = (m_pState->pressed == m_pState->pressedCounter) ?  m_pState->style.buttonPressed : m_pState->style.buttonNormal;
				Render::FillRect(window.x, window.y, window.x + window.width, window.y + window.height, m_pState->style.textBackground);
				Render::FillRect(activeWindow.x, activeWindow.y, activeWindow.x + activeWindow.width, activeWindow.y + activeWindow.height, colour);
			}

			if (!(flags & BORDERLESS))
			{
				Render::DrawHLine(window.x, window.y, window.x + window.width - 1, m_pState->style.layoutShadow);
				Render::DrawVLine(window.x, window.y, window.y + window.height - 1, m_pState->style.layoutShadow);
				Render::DrawVLine(window.x + window.width - 1, window.y, window.y + window.height, m_pState->style.layoutHighlight);
				Render::DrawHLine(window.x, window.y + window.height - 1, window.x + window.width, m_pState->style.layoutHighlight);
			}
		}

		bool triggered = false;

		bool inside = (activeWindow.x <= m_pState->currentInput.mouseX && m_pState->currentInput.mouseX < activeWindow.x + activeWindow.width
					&& activeWindow.y <= m_pState->currentInput.mouseY && m_pState->currentInput.mouseY < activeWindow.y + activeWindow.height);

		if (inside)
			m_pState->UpdateHot(flags & FLOAT);

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool previousMouse = (flags & R_MOUSE) ? m_pState->previousInput.mouseR : m_pState->previousInput.mouseL;

		bool click = !(flags & GHOSTED) && (currentMouse && !previousMouse);

		if (m_pState->previousHot == m_pState->hotCounter)
		{
			if (click)
			{
				m_pState->pressed = m_pState->pressedCounter;
			}
		}

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			static int offsetY;

			if (click)
			{
				offsetY = m_pState->currentInput.mouseY - activeWindow.y;
			}

			activeOffset = m_pState->currentInput.mouseY - window.y - offsetY;

			if (!currentMouse)
			{
				m_pState->pressed = -1;
				triggered = true;
			}
		}

		activeOffset = Ut::Clamp(activeOffset, 0, window.height - activeWindow.height);
		offset = (int) (activeOffset / proportion + 0.5f);

		m_pState->hotCounter++;
		m_pState->pressedCounter++;

		return triggered;
	}

	bool Ui::DoHotBox(Window& window, int& mouseX, int& mouseY, bool& click, bool& release, bool& rClick, bool& rRelease, uint32 flags)
	{
		bool triggeredL = DoHotBox(window, mouseX, mouseY, click, release, flags);
		m_pState->hotCounter--;
		bool triggeredR = DoHotBox(window, mouseX, mouseY, rClick, rRelease, flags|R_MOUSE);

		return triggeredL || triggeredR;
	}

	bool Ui::DoHotBox(Window& window, int& mouseX, int& mouseY, bool& click, bool& release, uint32 flags)
	{
		bool triggered = false;

		m_pState->layoutStack.back()->AddItem(Imgui::USE_INPUT_XY, &window);

		bool inside = (window.x <= m_pState->currentInput.mouseX && m_pState->currentInput.mouseX < window.x + window.width
					&& window.y <= m_pState->currentInput.mouseY && m_pState->currentInput.mouseY < window.y + window.height);

		if (inside)
			m_pState->UpdateHot(flags & FLOAT);

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool previousMouse = (flags & R_MOUSE) ? m_pState->previousInput.mouseR : m_pState->previousInput.mouseL;

		click = !(flags & GHOSTED) && (currentMouse && !previousMouse);
		release = false;

		if ((m_pState->previousHot == m_pState->hotCounter && m_pState->pressed == -1) || m_pState->pressed == m_pState->pressedCounter)
		{
			triggered = true;
			mouseX = m_pState->currentInput.mouseX;
			mouseY = m_pState->currentInput.mouseY;

			if (click)
			{
				m_pState->pressed = m_pState->pressedCounter;
			}
		}

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			if (!currentMouse)
			{
				m_pState->pressed = -1;
				release = true;
			}
		}

		m_pState->hotCounter++;
		m_pState->pressedCounter++;

		return triggered;
	}

	bool Ui::DoDragBox(Window& window, bool& active, uint32 flags)
	{
		bool triggered = false;

		bool inside = (window.x <= m_pState->currentInput.mouseX && m_pState->currentInput.mouseX < window.x + window.width
					&& window.y <= m_pState->currentInput.mouseY && m_pState->currentInput.mouseY < window.y + window.height);

		if (inside)
			m_pState->UpdateHot(flags & FLOAT);

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool previousMouse = (flags & R_MOUSE) ? m_pState->previousInput.mouseR : m_pState->previousInput.mouseL;

		bool click = !(flags & GHOSTED) && (currentMouse && !previousMouse);

		if (m_pState->previousHot == m_pState->hotCounter)
		{
			if (click)
			{
				m_pState->pressed = m_pState->pressedCounter;
			}
		}

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			static Window currentWindow;
			static int offsetX;
			static int offsetY;

			if (click)
			{
				currentWindow = window;

				if (!(flags & NO_OFFSET))
				{
					offsetX = m_pState->currentInput.mouseX - currentWindow.x;
					offsetY = m_pState->currentInput.mouseY - currentWindow.y;
				}
				else
				{
					offsetX = 0;
					offsetY = 0;
				}
			}

			window.x = m_pState->currentInput.mouseX - offsetX;
			window.y = m_pState->currentInput.mouseY - offsetY;
			active = true;

			if (!currentMouse)
			{
				m_pState->pressed = -1;
				triggered = true;
			}
		}

		m_pState->hotCounter++;
		m_pState->pressedCounter++;

		return triggered;
	}

	bool Ui::DoButton(const char* text, uint32 flags, Window* pWindow)
	{
		bool triggered = false;

		uint32 textColour = m_pState->style.buttonText;

		if (flags & GHOSTED)
			textColour = m_pState->style.buttonTextGhosted;

		Render::Surface pSurface(0);
		Render::Surface pSurfaceShadow(0);

		int width = 0;
		int height = 0;

		if (text)
		{
			width = GetWidth(m_pState->style.GetFont(), text) + m_pState->style.margin * 2;
			height = GetHeight(m_pState->style.GetFont(), text) + m_pState->style.margin;
		}

		Window window;

		if (pWindow)
			window = *pWindow;

		window.width = max(width, window.width);
		window.height = max(height, window.height);
		
		m_pState->layoutStack.back()->AddItem(flags, &window);

		if (pWindow)
			*pWindow = window;

		if (flags & REPEAT)
			m_pState->hotCounter--;

		bool inside = (window.x <= m_pState->currentInput.mouseX && m_pState->currentInput.mouseX < window.x + window.width
					&& window.y <= m_pState->currentInput.mouseY && m_pState->currentInput.mouseY < window.y + window.height);

		if (inside)
			m_pState->UpdateHot(flags & FLOAT);

		bool currentMouse = (flags & R_MOUSE) ? m_pState->currentInput.mouseR : m_pState->currentInput.mouseL;
		bool previousMouse = (flags & R_MOUSE) ? m_pState->previousInput.mouseR : m_pState->previousInput.mouseL;

		bool click = !(flags & GHOSTED) && (currentMouse && (!previousMouse || (flags & ON_MOUSE_UP)));

		if (m_pState->previousHot == m_pState->hotCounter)
		{
			if (click)
			{
				if (flags & ON_MOUSE_DOWN)
				{
					triggered = true;
				}
				else
				{
					m_pState->pressed = m_pState->pressedCounter;
				}
			}
		}

		if (m_pState->pressed == m_pState->pressedCounter)
		{
			if (!currentMouse)
			{
				m_pState->pressed = -1;

				if (inside)
				{
					triggered = true;
				}
			}

			if ((flags & ON_MOUSE_UP) && !inside)
			{
				m_pState->pressed = -1;
			}
		}

		// Render
		if (window.width > 0 && window.height > 0)
		{
			if (!(flags & EMPTY))
			{
				uint32 colour = (m_pState->pressed == m_pState->pressedCounter) ? 
								m_pState->style.buttonPressed : 
								(flags & SELECTED) ? m_pState->style.buttonSelected : m_pState->style.buttonNormal;

				Render::FillRect(window.x, window.y, window.x + window.width, window.y + window.height, colour);

				if (flags & SHADOW)
					Render::DrawText(window.x + 1 + m_pState->style.margin, window.y + 2, m_pState->style.GetFont(), text, m_pState->style.buttonTextShadow);

				Render::DrawText(window.x + m_pState->style.margin, window.y + 1, m_pState->style.GetFont(), text, textColour);
			}

			if (!(flags & BORDERLESS))
			{
				Render::DrawHLine(window.x, window.y, window.x + window.width, m_pState->style.layoutHighlight);
				Render::DrawVLine(window.x, window.y, window.y + window.height, m_pState->style.layoutHighlight);
				Render::DrawVLine(window.x + window.width - 1, window.y, window.y + window.height, m_pState->style.layoutShadow);
				Render::DrawHLine(window.x, window.y + window.height - 1, window.x + window.width, m_pState->style.layoutShadow);
			}
		}

		m_pState->hotCounter++;
		m_pState->pressedCounter++;

		return triggered;
	}

	void Ui::DoLabel(const char* text, uint32 flags)
	{
		uint32 textColour = m_pState->style.buttonText;

		Window window;
		window.width = GetWidth(m_pState->style.GetFont(), text) + m_pState->style.margin * 2;
		window.height = GetHeight(m_pState->style.GetFont(), text) + m_pState->style.margin;

		m_pState->layoutStack.back()->AddItem(flags, &window);

		// Render
		if (window.width > 0 && window.height > 0)
		{
			if (!(flags & EMPTY))
			{
				uint32 colour = (flags & TITLE) ? m_pState->style.titleBackground : (flags & BUTTON) ? m_pState->style.buttonNormal : m_pState->style.layoutBackground;
				Render::FillRect(window.x, window.y, window.x + window.width, window.y + window.height, colour);
			}
		
			Render::DrawText(window.x + 1 + m_pState->style.margin, window.y + 1 + m_pState->style.margin, m_pState->style.GetFont(), text, m_pState->style.buttonTextShadow);
			Render::DrawText(window.x + m_pState->style.margin, window.y + m_pState->style.margin, m_pState->style.GetFont(), text, textColour);
		}
	}

	void Ui::UiState::BeginLayout(LayoutType layoutType, uint32 flags, const Window* pWindow) 
	{
		Window window;

		if (flags & FORCE_FOCUS) 
			this->hot = -1;

		if (pWindow)
		{
			window = *pWindow;

			if (flags & USE_CACHED_SIZE)
			{
				Window cachedWindow = this->layoutWindows[this->layoutCounter];
				window.width = cachedWindow.width;
				window.height = cachedWindow.height;
			}
		}
		else
		{
			window = this->layoutWindows[this->layoutCounter];
		}

		if (flags & INDENT)
			window.x = pWindow->x;

		if (!this->layoutStack.empty())
		{
			this->layoutStack.back()->AddItem(flags, &window);
		}

		// Render
		if (window.width > 0 && window.height > 0)
		{
			if (!(flags & EMPTY))
				Render::FillRect(window.x, window.y, window.x + window.width, window.y + window.height, this->style.layoutBackground);

			if (!(flags & BORDERLESS))
			{
				Render::DrawHLine(window.x, window.y, window.x + window.width - 1, this->style.layoutHighlight);
				Render::DrawVLine(window.x, window.y, window.y + window.height - 1, this->style.layoutHighlight);
				Render::DrawVLine(window.x + window.width - 1, window.y, window.y + window.height, this->style.layoutShadow);
				Render::DrawHLine(window.x, window.y + window.height - 1, window.x + window.width, this->style.layoutShadow);
			}
		}

		Layouts::LayoutBase* pLayout;

		switch (layoutType)
		{
			case LayoutType::FIXED_WINDOW: pLayout = new Layouts::FixedWindow(this); break;
			case LayoutType::HORIZONTAL_LIST: pLayout = new Layouts::HorizontalList(this); break;
			case LayoutType::VERTICAL_LIST: pLayout = new Layouts::VerticalList(this); break;
			case LayoutType::TABLE: pLayout = new Layouts::Table(this); break;
		}

		pLayout->Begin(window, flags);
		this->layoutStack.push_back(pLayout);
		this->PushClipRect(window);

		if (layoutType == LayoutType::TABLE)
		{
			TableLayout* pTable = &this->layoutTables[this->layoutCounter];
			((Layouts::Table*) this->layoutStack.back())->SetTableLayout(pTable);
		}

		this->layoutCounter++;
	}

	const Window& Ui::GetVisibleWindow() const
	{
		return m_pState->layoutStack.back()->GetWindow();
	}

	const Window& Ui::GetFullWindow() const
	{
		return m_pState->layoutWindows[m_pState->layoutStack.back()->GetLayoutCounter()];
	}

	void Ui::UiState::EndLayout(Window* pWindow) 
	{
		Layouts::LayoutBase* pLayout = this->layoutStack.back();
		pLayout->End();
		this->layoutStack.pop_back();
		this->PopClipRect();

		if (pWindow)
			*pWindow = pLayout->GetWindow();

		this->layoutWindows[pLayout->GetLayoutCounter()] = pLayout->GetWindow();

		delete pLayout;
	}

	void Ui::OnEvent(const App::Event* pEvent) 
	{
		switch(App::GetType(pEvent)) 
		{
			case App::EVENT_KEY_DOWN: 
			{
				m_pState->OnKeyDown(App::GetKeyDownEvent(pEvent).unicode);
				break;
			}
		}
	}
}

